<template>
  <canvas id="viewport" ref="canvasRef"></canvas>
  <ViewportInfo></ViewportInfo>
  <BViewHelper></BViewHelper>
  <BContextmenu ref="contextMenuRef"></BContextmenu>
</template>
<script setup lang="ts">
import { nextTick, onMounted, ref } from 'vue'
import {
  Group,
  PerspectiveCamera,
  Scene,
  WebGLRenderer,
  AmbientLight,
  DirectionalLight
} from 'three'
import {
  CSS2DRenderer,
  EffectComposer,
  OrbitControls,
  TransformControls
} from 'three/examples/jsm/Addons'
import { useViewportStore } from '@renderer/stores/viewport'
import raycaster from './raycaster'
import transform from './transform'
import heightlight from './highlight'
import controlsTarget from './controlsTarget'
import ViewportInfo from './viewportInfo.vue'
import BViewHelper from './ViewHelper.vue'
import BContextmenu from '@renderer/components/b-contextmenu.vue'
import addNodes from './addNodes'

const {
  setCanvas,
  setScene,
  setPublicGroup,
  setNotPublicGroup,
  setCamera,
  setCss2DRenderer,
  setRenderer,
  setComposer,
  setOrbitControls,
  setTransformControls
} = useViewportStore()
const canvasRef = ref()
const contextMenuRef = ref()
onMounted(() => {
  // 初始化场景
  const { clientWidth, clientHeight } = canvasRef.value
  const renderer = new WebGLRenderer({
    canvas: canvasRef.value,
    antialias: true,
    alpha: true
  })
  renderer.setPixelRatio(window.devicePixelRatio)
  renderer.setSize(clientWidth, clientHeight)
  const camera = new PerspectiveCamera(75, clientWidth / clientHeight)
  camera.near = 0.1
  camera.far = 1000000
  camera.updateProjectionMatrix()

  const scene = new Scene()
  // 创建一个公开组
  const publicGroup = new Group()
  publicGroup.name = 'publicGroup'
  scene.add(publicGroup)
  // 创建一个内部使用，外部不可见的组
  const notPublicGroup = new Group()
  notPublicGroup.name = 'notPublicGroup'
  scene.add(notPublicGroup)

  const light = new AmbientLight(0xeeeeee) // 柔和的白光
  notPublicGroup.add(light)
  const directionalLight = new DirectionalLight(0xf4f4f4, 1)
  notPublicGroup.add(directionalLight)
  directionalLight.position.set(10, 10000, 50)

  const css2DRenderer = new CSS2DRenderer()
  css2DRenderer.setSize(clientWidth, clientHeight)
  css2DRenderer.domElement.style.position = 'absolute'
  css2DRenderer.domElement.setAttribute('class', 'css2DRenderer')
  css2DRenderer.domElement.style.top = '0px'
  canvasRef.value.parentNode.appendChild(css2DRenderer.domElement)
  camera.position.z = 5
  const orbitControls = new OrbitControls(camera, css2DRenderer.domElement)
  // orbitControls.enableDamping = true
  // 初始化变换控制器
  const transformControls = new TransformControls(camera, css2DRenderer.domElement)
  transformControls.addEventListener('dragging-changed', function (event) {
    orbitControls.enabled = !event.value
  })
  // 初始化后处理器
  const composer = new EffectComposer(renderer)
  composer.setPixelRatio(window.devicePixelRatio)
  // 加入状态管理
  setCanvas(canvasRef.value)
  setScene(scene)
  setCamera(camera)
  setCss2DRenderer(css2DRenderer)
  setRenderer(renderer)
  setOrbitControls(orbitControls)
  setTransformControls(transformControls)
  setPublicGroup(publicGroup)
  setNotPublicGroup(notPublicGroup)
  setComposer(composer)
  // 扩展
  const { setContextMenuRef } = raycaster()
  setContextMenuRef(contextMenuRef.value)
  transform()
  heightlight()
  controlsTarget()

  // 动起来
  function animate() {
    orbitControls.update()
    // renderer.render(scene, camera)
    composer.render()
    css2DRenderer.render(scene, camera)
    requestAnimationFrame(animate)
  }

  animate()

  nextTick(() => {
    addNodes()
  })

  // Resize
  window.addEventListener('resize', () => {
    const { clientWidth, clientHeight } = canvasRef.value
    camera.aspect = clientWidth / clientHeight
    camera.updateProjectionMatrix() // 更新摄像机投影矩阵
    renderer.setSize(clientWidth, clientHeight)
    css2DRenderer.setSize(clientWidth, clientHeight)
  })
})
</script>
<style lang="scss" scoped>
#viewport {
  width: 100% !important;
  height: 100% !important;
}
</style>
